export type Dictionary<T = any> = Record<string, T>

export type Data<T = any> = T | T[] 

export type AsyncDataResult<T = any> = Promise<T | T[]>

export type PromiseArray<T = any> = Promise<T>[]

export type PromiseBoolean = AsyncDataResult<boolean>

export type AsyncVoid = AsyncDataResult<void>

export type OrderDirection = 'asc' | 'desc'

export interface TableOperationParams {
  table: string
}

export interface ColumnOperationParams extends TableOperationParams {
  name: string
}

export interface RenameOperationParams extends TableOperationParams {
  from: string
  to: string
}

export interface RecordOperationParams extends TableOperationParams {
  data: any
  where?: any
}

export interface PaginationQuery {
  size?: number
  no?: number
  where?: Dictionary
  orderBy?: SortCriteria[]
}

export interface SortCriteria {
  field: string
  direction?: OrderDirection
}

export interface Join {
  table: string
  left: string
  right: string
}

export interface AggregateParams extends TableOperationParams {
  column?: string
  conditions?: Dictionary
  groupBy?: string
}

export interface SelectRecordsParams extends TableOperationParams {
  conditions: any
  limit?: number
  offset?: number
  orderBy?: SortCriteria[]
}

export interface SelectJoinRecordParams extends SelectRecordsParams {
  joins: Join[]
}

export interface ExecuteRawSqlParams {
  sql: string
  params?: any[]
}

export interface AddColumnParams extends ColumnOperationParams {
  type: string
}

export interface DropColumnParams extends ColumnOperationParams {}

export interface RenameColumnParams extends RenameOperationParams {}

export interface ColumnExistsParams extends ColumnOperationParams {}

export interface CreateTableParams {
  name: string
  cols: Dictionary
}

export interface DropTableParams {
  name: string
}

export interface TableExistsParams {
  name: string
}

export interface TruncateTableParams {
  name: string
}

export interface RenameTableParams extends RenameOperationParams {}

export interface InsertRecordParams extends RecordOperationParams {}

export interface UpdateRecordParams extends RecordOperationParams {}

export interface DeleteRecordParams {
  table: string
  where: any
}

export interface SaveEntityParams<T = any> {
  table: string
  data: T
}

export interface UpdateEntityParams extends RecordOperationParams {}

export interface DeleteEntityParams {
  table: string
  id: string
}

export interface PaginateEntityParams {
  table: string
  pager: PaginationQuery
}

export interface SelectOneRecordParams {
  table: string
  conditions: any
}

export interface GetTableColumnsParams {
  name: string
}

export interface GetTableUsedParams extends TableOperationParams {}

export interface SetTableUsedParams extends TableOperationParams {
  primaryKeyValue: string
}

export interface IAggregate {
  count(params: AggregateParams): AsyncDataResult<number>
  sum(params: AggregateParams): AsyncDataResult<number>
  avg(params: AggregateParams): AsyncDataResult<number>
  max(params: AggregateParams): AsyncDataResult<number>
  min(params: AggregateParams): AsyncDataResult<number>
}

export interface IBase {
  uuid(): AsyncDataResult<string>
  types(): AsyncDataResult<string>
  showPrimaryKey(): AsyncDataResult<string>  
  showTables(): AsyncDataResult<string>
}

export interface IColumn {
  add(params: AddColumnParams): AsyncVoid
  drop(params: DropColumnParams): AsyncVoid
  exists(params: ColumnExistsParams): AsyncVoid
  rename(params: RenameColumnParams): AsyncVoid
}

export interface ICrud {
  insert(params: InsertRecordParams): AsyncVoid
  update(params: UpdateRecordParams): AsyncVoid
  drop(params: DeleteRecordParams): AsyncDataResult<string>
}

export interface IEntity<E = any> {
  save(params: SaveEntityParams<E>): AsyncDataResult
  update(params: UpdateEntityParams): AsyncDataResult
  drop(params: DeleteEntityParams): AsyncDataResult<string>
  page(params: PaginateEntityParams): AsyncDataResult
}

export interface INative {
  raw(params: ExecuteRawSqlParams): AsyncDataResult
}

export interface IQuery {
  selectOne(params: SelectOneRecordParams): AsyncDataResult
  select(params: SelectRecordsParams): AsyncDataResult
  selectJoin(params: SelectJoinRecordParams): AsyncDataResult
}

export interface ITable {
  create(params: CreateTableParams): AsyncVoid
  drop(params: DropTableParams): AsyncVoid
  exists(params: TableExistsParams): PromiseBoolean
  truncate(params: TruncateTableParams): AsyncVoid
  rename(params: RenameTableParams): AsyncVoid 
  columns(params: GetTableColumnsParams): AsyncDataResult<string>
}

export interface IUsed {
  get(table: string): AsyncDataResult<number>
  use(table: string, id: string): AsyncVoid
}

